package jt

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"net/url"
	"strconv"
	"strings"

	"github.com/dontls/xproto"
)

const (
	kResSuc = iota
	kResFailed
	kResError
	kResUnsupport
	kResAlarmAck
)

func toError(code uint8) string {
	var err string
	switch code {
	case kResFailed:
		err = "failed"
	case kResError:
		err = "message error"
	case kResUnsupport:
		err = "unsupport"
	case kResAlarmAck:
		err = "alarm ack"
	}
	return err
}

type jtBytes struct {
	jtVer int // jt对应版本 1: jt808-2019
	pos   int
	Bytes []byte
}

func (b *jtBytes) Slice(size int) (o jtBytes) {
	o.pos = 0
	o.Bytes = b.toArray(size)
	return
}

// addDateTime 添加时间
// 2006-01-02 15:04:05 -> 060102150405 -> Bcd
func (b *jtBytes) addDateTime(v string) {
	tm := v[2:4] + v[5:7] + v[8:10] + v[11:13] + v[14:16] + v[17:]
	b.addBCD(number2bcd(tm))
}

func (b *jtBytes) addByte(v uint8) {
	b.Bytes = append(b.Bytes, v)
}

func (b *jtBytes) addIntByte(v int) {
	b.Bytes = append(b.Bytes, byte(v))
}

func (b *jtBytes) addWord(v uint16) {
	b.Bytes = append(b.Bytes, byte(v>>8))
	b.Bytes = append(b.Bytes, byte(v))
}

func (b *jtBytes) addDWord(v uint32) {
	b.Bytes = append(b.Bytes, byte(v>>24))
	b.Bytes = append(b.Bytes, byte(v>>16))
	b.Bytes = append(b.Bytes, byte(v>>8))
	b.Bytes = append(b.Bytes, byte(v))
}

func (b *jtBytes) add64BITS(v uint64) {
	b.Bytes = append(b.Bytes, byte(v>>56))
	b.Bytes = append(b.Bytes, byte(v>>48))
	b.Bytes = append(b.Bytes, byte(v>>40))
	b.Bytes = append(b.Bytes, byte(v>>32))
	b.Bytes = append(b.Bytes, byte(v>>24))
	b.Bytes = append(b.Bytes, byte(v>>16))
	b.Bytes = append(b.Bytes, byte(v>>8))
	b.Bytes = append(b.Bytes, byte(v))
}

func (b *jtBytes) addBCD(bcd []byte) {
	b.addBytes(bcd)
}

func (b *jtBytes) addBytes(bs []byte) {
	b.Bytes = append(b.Bytes, bs...)
}

// lt length type 0：无需legth， 1： byte length 2： word legth
func (b *jtBytes) addString(s string, ltype int) {
	s1 := toGBK(s)
	if ltype == 1 {
		b.addByte(uint8(len(s1)))
	} else if ltype == 2 {
		b.addWord(uint16(len(s1)))
	}
	b.Bytes = append(b.Bytes, s1...)
}

// 这里判断如果是1;2;3;4多于1个通道搜索全部
func (b *jtBytes) addChannel(chls string) {
	arr := strings.Split(chls, ";")
	if len(arr) > 1 {
		b.addByte(0)
	} else {
		ch, _ := strconv.Atoi(chls)
		b.addByte(uint8(ch))
	}
}

func (b *jtBytes) addTcpServer(addr string) error {
	arr := strings.Split(addr, ":")
	if len(arr) != 2 {
		return xproto.ErrParam
	}
	b.addString(arr[0], 1)
	port, _ := strconv.Atoi(arr[1])
	b.addWord(uint16(port)) // tcp端口号
	return nil
}

func (b *jtBytes) toByte() uint8 {
	val := b.Bytes[b.pos]
	b.pos++
	return val
}

func (b *jtBytes) toWord() uint16 {
	val := binary.BigEndian.Uint16(b.Bytes[b.pos:])
	b.pos += 2
	return val
}

func (b *jtBytes) toDWord() uint32 {
	val := binary.BigEndian.Uint32(b.Bytes[b.pos:])
	b.pos += 4
	return val
}

func (b *jtBytes) toArray(size int) []byte {
	b.pos += size
	return b.Bytes[b.pos-size : b.pos]
}

func (j *jtBytes) toString(n int) string {
	return toUTF8(bytes.TrimRight(j.toArray(n), "\x00"))
}

func (b *jtBytes) toBytes() []byte {
	return b.Bytes[b.pos:]
}

// func (b *jtBytes) toString(b []byte) string {
// 	return toUTF8(b)
// }

const (
	jtFlag              = 0x7e
	jtHeaderLength      = 12
	jtprotocolAuthority = "abcdef"
)

func (c *Client) jtPacketBytes(msgID uint16, b []byte) []byte {
	var jb jtBytes
	jb.addWord(msgID)
	jb.addWord(uint16(1<<14 + len(b)))
	if c.Msg.Property.VerFlag == 1 {
		jb.addByte(c.Msg.Version)
	}
	jb.addBCD(c.Msg.PhoneNumberBcd)
	c.sequence++
	jb.addWord(c.sequence) // 服务流水号
	jb.addBytes(b)
	// 计算checksum
	jb.addByte(checkSum(jb.Bytes))
	var rdata []byte
	rdata = append(rdata, 0x7E)
	for _, v := range jb.Bytes {
		if v == 0x7D {
			rdata = append(rdata, 0x7D)
			rdata = append(rdata, 0x01)
		} else if v == 0x7E {
			rdata = append(rdata, 0x7D)
			rdata = append(rdata, 0x02)
		} else {
			rdata = append(rdata, v)
		}
	}
	rdata = append(rdata, 0x7E)
	return rdata
}

// 解析协议头
func decToJtBytes(b []byte) *jtBytes {
	// 转码
	r, j := &jtBytes{pos: 0}, 0
	r.Bytes = make([]byte, len(b))
	for i := 0; i < len(b); i++ {
		if b[i] == 0x7d && b[i+1] == 0x01 {
			r.Bytes[j] = 0x7d
			i++
		} else if b[i] == 0x7d && b[i+1] == 0x02 {
			r.Bytes[j] = 0x7e
			i++
		} else {
			r.Bytes[j] = b[i]
		}
		j++
	}
	r.Bytes = r.Bytes[:j-1] // 去掉checksum
	return r
}

// jtMsgProperty 属性
// 0-9bit 字节消息体长度
// 10-12bit 数据加密方式
// 13bit 分包
// 14-15bit 保留 （jt808-2019 bit14 版本表示）
type jtMsgProperty struct {
	Length int
	// 10-12bit
	// 三位都为0  消息体不加密
	// 10bit 为1 消息体RSA加密
	Encryption uint8
	SubFlag    uint8
	VerFlag    uint8
}

func toMsgProperty(property uint16) jtMsgProperty {
	return jtMsgProperty{
		Length:     int(property & 0x03FF),
		Encryption: uint8((property >> 10) & 0x07),
		SubFlag:    uint8((property >> 13) & 0x01),
		VerFlag:    uint8((property >> 14) & 0x01),
	}
}

// jtMsgPacket
// 大端对齐
type jtMsgPacket struct {
	ID             uint16
	Property       jtMsgProperty
	PhoneNumberBcd []byte //6位bcd 响应时无需编码
	SerialNum      uint16
	Total          uint16
	Cur            uint16
	Data           []byte
	Version        uint8
	mBody          map[uint16][]byte // 分包数据
}

func (c *Client) MsgData() *jtBytes {
	if c.Msg.Total == 0 {
		return c.jtBytes
	}
	if c.Msg.Total > c.Msg.Cur {
		return nil
	}
	return &jtBytes{Bytes: c.Msg.Data, pos: 0}
}

func (m *jtMsgPacket) Unmarshal(b []byte) *jtBytes {
	j := decToJtBytes(b)
	m.ID = j.toWord()
	m.Property = toMsgProperty(j.toWord())
	if m.Property.VerFlag == 1 { // jt808-2019
		m.Version = j.toByte()
		m.PhoneNumberBcd = j.toArray(10)
	} else {
		m.PhoneNumberBcd = j.toArray(6)
	}
	j.jtVer = int(m.Version)
	if m.Property.Length < 37 {
		j.jtVer = -1 //2011
	}
	m.SerialNum = j.toWord()
	// 分包
	if m.Property.SubFlag > 0 {
		m.Total = j.toWord()
		m.Cur = j.toWord()
	}
	m.Data = j.toBytes()
	if m.Total > 0 {
		key := m.SerialNum - m.Cur
		data := m.mBody[key]
		data = append(data, m.Data...)
		if m.Total == m.Cur {
			m.Data = data
			delete(m.mBody, key)
		} else {
			m.mBody[key] = data
		}
	}
	return j
}

// jtRegister 注册信息
type jtRegister struct {
	Provincial     uint16 // 省
	City           uint16 // 市
	ManufacturerID []byte // 制造商ID
	Model          []byte // 终端型号
	ID             []byte // 终端ID
	PlateColor     uint8  // 车牌颜色
	PlateNo        string // 车牌
}

func (b *jtBytes) toRegister() *jtRegister {
	var reg jtRegister
	reg.Provincial = b.toWord()
	reg.City = b.toWord()
	if b.jtVer == 1 {
		reg.ManufacturerID = b.toArray(11)
		reg.Model = b.toArray(30)
		reg.ID = b.toArray(30)
	} else {
		reg.ManufacturerID = b.toArray(5)
		if b.jtVer < 0 {
			reg.Model = b.toArray(8)
		} else {
			reg.Model = b.toArray(20)
		}
		reg.ID = b.toArray(7)
	}
	reg.PlateColor = b.toByte()
	reg.PlateNo = toUTF8(b.toBytes())
	return &reg
}

type jtTerminalProperty struct {
	Type           uint16 `json:"type"`
	ManufacturerId []byte `json:"manufacturerId"` // 制造商Id
	Model          []byte `json:"model"`          // 型号
	Id             []byte `json:"id"`             // 终端Id
	ICCID          []byte `json:"iccid"`          // 终端 SIM 卡 ICCID
	hardVerLength  byte   `json:"-"`
	HardVer        string `json:"hardVer"`
	fwVerLength    byte   `json:"-"`
	FwVer          string `json:"fwVer"`
	GNSS           byte   `json:"gnss"`
	GPRS           byte   `json:"gprs"`
}

func (b *jtBytes) toTerminalProperty() *jtTerminalProperty {
	var info jtTerminalProperty
	info.Type = b.toWord()
	info.ManufacturerId = b.toArray(5)
	if b.jtVer == 1 {
		info.Model = b.toArray(30)
		info.Id = b.toArray(30)
	} else {
		info.Model = b.toArray(20)
		info.Id = b.toArray(7)
	}
	info.ICCID = b.toArray(10)
	info.hardVerLength = b.toByte()
	info.HardVer = toUTF8(b.toArray(int(info.hardVerLength)))
	info.fwVerLength = b.toByte()
	info.FwVer = toUTF8(b.toArray(int(info.fwVerLength)))
	info.GNSS = b.toByte()
	info.GPRS = b.toByte()
	return &info
}

type jtTerminalUpgrade struct {
	Type   uint8 `json:"type"`
	Result uint  `json:"result"`
}

func (b *jtBytes) toTerminalUpgrade() *jtTerminalUpgrade {
	var info jtTerminalUpgrade
	info.Type = b.toByte()
	info.Result = uint(b.toByte())
	return &info
}

// 8.21 临时位置跟踪控制
type Jt8202 struct {
	Interval      uint16 `json:"interval"`
	EffectiveTime uint32 `json:"effectiveTime"`
}

// 8.22 人工确认报警消息
type Jt8203 struct {
	AlarmSerial uint16 `json:"alarmSerial"`
	AlarmType   uint32 `json:"alarmType"`
}

// 8.23 文本信息下发
type Jt8300 struct {
	Flag uint8  `json:"flag"`
	Text string `json:"text"`
}

// 8.23 文本信息下发
type Jt8302 struct {
	Flag     uint8  `json:"flag"`
	Question string `json:"text"`
	Answers  []struct {
		Id      uint8  `json:"id"`
		Content string `json:"content"`
	} `json:"answers"`
}

// 8.28 信息点播菜单设置
type Jt8303 struct {
	Type    uint8 `json:"type"`
	Message []struct {
		Type uint8  `json:"type"`
		Name string `json:"name"`
	} `json:"message"`
}

// 8.30 信息服务
type Jt8304 struct {
	Type    uint8  `json:"type"`
	Content string `json:"content"`
}

// 8.31 电话回拨
type Jt8400 struct {
	Type        uint8  `json:"type"`
	PhoneNumber string `json:"phoneNumber"`
}

// 8.32 设置电话本
type Jt8401 struct {
	Type     uint8 `json:"type"`
	Contacts []struct {
		Type        uint8  `json:"type"`
		PhoneNumber string `json:"phoneNumber"`
		Name        string `json:"name"`
	} `json:"contacts"`
}

// 圆形区域
type Jt8600 struct {
	Action  uint8 `json:"action"`
	Regions []struct {
		ID          uint32  `json:"id"`
		Attr        uint16  `json:"attr"`
		La          float32 `json:"latitude"`
		Lo          float32 `json:"longitude"`
		Ra          uint32  `json:"radius"`
		St          string  `json:"startTime"`
		Et          string  `json:"endTime"`
		MaxSpd      uint16  `json:"maxSpeed"`
		KeepTime    uint8   `json:"keepTime"`
		MaxNightSpd uint16  `json:"maxNightSpeed"`
		Name        string  `json:"name"`
	} `json:"regions"`
}

// 矩形区域
type Jt8602 struct {
	Action  uint8 `json:"action"`
	Regions []struct {
		ID          uint32  `json:"id"`
		Attr        uint16  `json:"attr"`
		LeftTopLa   float32 `json:"leftTopLatitude"`
		LeftTopLo   float32 `json:"leftTopLongitude"`
		RightBotLa  float32 `json:"rightBotLatitude"`
		RightBotLo  float32 `json:"rightBotLongitude"`
		St          string  `json:"startTime"`
		Et          string  `json:"endTime"`
		MaxSpd      uint16  `json:"maxSpeed"`
		KeepTime    uint8   `json:"keepTime"`
		MaxNightSpd uint16  `json:"maxNightSpeed"`
		Name        string  `json:"name"`
	} `json:"regions"`
}

// 多边形区域
type Jt8604 struct {
	ID       uint32 `json:"id"`
	Attr     uint16 `json:"attr"`
	St       string `json:"startTime"`
	Et       string `json:"endTime"`
	MaxSpd   uint16 `json:"maxSpeed"`
	KeepTime uint8  `json:"keepTime"`
	Dots     []struct {
		La float32 `json:"latitude"`
		Lo float32 `json:"longitude"`
	} `json:"dots"`
	MaxNightSpd uint16 `json:"maxNightSpeed"`
	Name        string `json:"name"`
}

type Jt8601O3 struct {
	IDs []uint32 `json:"id"`
}

// 音视频属性
type jt0x1003 struct {
	Audio struct {
		Encoder     uint8  `json:"encoder"`
		Chls        uint8  `json:"chls"`
		SampleRate  uint8  `json:"sampleRate"`
		SampleBit   uint8  `json:"sampleBit"`
		FrameLength uint16 `json:"frameLength"`
		MaxChls     uint8  `json:"maxChls"`
	} `json:"audio"`
	Video struct {
		Enable  uint8 `json:"enable"`
		Encoder uint8 `json:"encoder"`
		MaxChls uint8 `json:"maxChls"`
	} `json:"video"`
}

// 实时音视频传输状态通知
type jt0x9105 struct {
	Channel  uint8 `json:"channel"`
	LossRate uint8 `json:"lossRate"`
}

// 上传乘客流量
type jt0x1005 struct {
	StartTime string `json:"startTime"`
	EndTime   string `json:"endTime"`
	Up        uint16 `json:"up"`
	Down      uint16 `json:"down"`
}

type jtRecFile struct {
	Chl       uint8
	StartTime string
	EndTime   string
	AlarmFlag int64
	Frame     uint8
	Stream    uint8
	Store     uint8
}

// jt1078协议文件格式 chl_sts_ets_alarm_Framestream_store
func (c *jtRecFile) parseFileName(filename string) ([]string, error) {
	if !strings.HasSuffix(filename, ".jh26") {
		return nil, errors.New("jt808 use virtual file .jh26")
	}
	arr := strings.Split(filename[5:], "_")
	if len(arr) < 7 {
		return nil, errors.New("file style: /chl_sts_ets_alarm_Framestream_store.j2")
	}
	c.Chl = strToUInt8(arr[0])
	c.StartTime = unixToTime(strToInt64(arr[1]))
	c.EndTime = unixToTime(strToInt64(arr[2]))
	c.AlarmFlag = strToInt64(arr[3])
	c.Frame = strToUInt8(arr[4])
	c.Stream = strToUInt8(arr[5])
	c.Store = strToUInt8(arr[6])
	return arr[7:], nil
}

func virtualRecFile(chl int, st, et int64, alrt uint64, ftype, stream, store uint8) string {
	return fmt.Sprintf("/%d_%d_%d_%v_%d_%d_%d.j2", chl, st, et, alrt, ftype, stream, store) // 虚拟文件
}

type jt0x9206 struct {
	Addr     string
	Port     uint16
	Usernmae string
	Password string
	Pathname string
	jtRecFile
	Net uint8
}

// chl_sts_ets_alarm_Framestream_store_net
func (c *jt0x9206) parseFileName(filename string) error {
	arr, err := c.jtRecFile.parseFileName(filename)
	if err != nil {
		return err
	}
	if len(arr) > 0 {
		c.Net = strToUInt8(arr[0])
	}
	return nil
}

// "ftp://admin:123456@172.16.50.219:21",
func (c *jt0x9206) parseFtpUrl(s string) error {
	l, err := url.Parse(s)
	if err != nil {
		return err
	}
	if strings.ToLower(l.Scheme) != "ftp" {
		return errors.New("ftp address style: ftp://admin:123456@192.168.1.1:21")
	}
	c.Usernmae = l.User.Username()
	c.Password, _ = l.User.Password()
	c.Addr = l.Hostname()
	c.Port = uint16(strToInt(l.Port()))
	return nil
}

// 高级驾驶辅助系统 苏标0x64
type jtAdvanceAssistance struct {
	Status        byte    `json:"status"`
	Alarm         byte    `json:"alarm"`
	Level         byte    `json:"level"`
	PreSpeed      byte    `json:"preSpeed"`
	Distance      byte    `json:"distance"`
	DeviationType byte    `json:"deviationType"`
	RoadSignType  byte    `json:"roadSignType"`
	RoadSignData  byte    `json:"roadSignData"`
	Speed         byte    `json:"speed"`
	Altitude      uint16  `json:"altitude"` // m
	Lo            float32 `json:"lo"`       // 4 byte, 10*6
	La            float32 `json:"la"`       // 4 byte, 10*6
	Time          string  `json:"time"`     //bcd 6
	Vehicel       uint16  `json:"vehicel"`
	ID            string  `json:"id"`  //30
	DTU           string  `json:"dtu"` //bcd 6
	Seq           byte    `json:"seq"`
	Num           byte
	// Reserved       [2]byte
}

func (j *jtBytes) toAdvanceAssistance() *jtAdvanceAssistance {
	var r jtAdvanceAssistance
	r.Status = j.toByte()
	r.Alarm = j.toByte()
	r.Level = j.toByte()
	r.PreSpeed = j.toByte()
	r.Distance = j.toByte()
	r.DeviationType = j.toByte()
	r.RoadSignType = j.toByte()
	r.RoadSignData = j.toByte()
	r.Speed = j.toByte()
	r.Altitude = j.toWord()
	r.Lo = float32(j.toDWord()) / 1000000
	r.La = float32(j.toDWord()) / 1000000
	r.Time = dtu(j.toArray(6))
	r.Vehicel = j.toWord()
	r.ID = j.toString(30)
	r.DTU = dtu(j.toArray(6))
	r.Seq = j.toByte()
	r.Num = j.toByte()
	return &r
}
